﻿/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkSystemState.h"
#include "MkLog.h"
#include "MkUtil.h"
#include <time.h>

CSystemState::CSystemState()
    : m_SystemCpuPercent(0.0f)
    , m_SystemMemPercent(0.0f)
    , m_StartTime(NowMkTime)
{
#ifdef VERSION
    m_Version = MkString(VERSION);
#else
    m_Version = "not set";
#endif
#ifndef _WIN32
    GetLinuxVersion();
    GetCpuInfo();
#endif
}

Uint32 CSystemState::Update()
{
#ifndef _WIN32
    UpdateMemInfo();
    GetState();
#endif
    return NoneError;
}

MkString CSystemState::GetSelfStartTime()
{
    MkString StrTime;
    m_StartTime.GetString(StrTime);
    return StrTime;
}

MkString CSystemState::GetSystemStartTime()
{
    MkString StrTime;
    m_SystemStartTime.GetString(StrTime);
    return StrTime;
}

double CSystemState::GetSystemCpuPercent()
{
    return m_SystemCpuPercent;
}

double CSystemState::GetSystemMemPercent()
{
    return m_SystemMemPercent;
}

Uint32 CSystemState::UpdateMemInfo()
{
    FILE* fp = fopen("/proc/meminfo", "r");
    if (!fp) {
        MkErrorLog("open meminfo:/proc/meminfo failed, ignore");
        return OpenFileFailed;
    }

    Uint32 MemTotal = 1;
    Uint32 MemFree = 0;
    char pbuf[LenHalfM] = { 0 };
    int nRet = fread(pbuf, 1, LenHalfM, fp);
    fclose(fp);
    if (nRet <= 0) {
        return SystemError;
    }
    MkVectorString VecStr;
    CMkUtil::StringSplit(pbuf, "\n", VecStr);
    for (size_t i = 0; i < VecStr.size(); i++) {
        if (MkString::npos != VecStr[i].find("MemTotal:")) {
            MemTotal = std::stoi(VecStr[i].substr(9));
        } else if (MkString::npos != VecStr[i].find("MemFree:")) {
            MemFree = std::stoi(VecStr[i].substr(8));
        }
    }
    m_SystemMemPercent = 1.0f - (float)MemFree / (float)MemTotal;
    return NoneError;
}

Uint32 CSystemState::GetLinuxVersion()
{
    FILE *fp = fopen("/proc/version", "r");
    char pbuf[Len512] = { 0 };
    if (!fp) {
        MkErrorLog("open version:/proc/version failed, ignore");
        return OpenFileFailed;
    }
    fread(pbuf, 1, sizeof(pbuf), fp);
    m_LinuxVersion = pbuf;
    fclose(fp);
    return NoneError;
}

Uint32 CSystemState::GetCpuInfo()
{
    FILE *fp = fopen("/proc/cpuinfo", "r");
    if (!fp) {
        MkErrorLog("open cpu info file: /proc/cpuinfo failed\n");
        return OpenFileFailed;
    }
    char pbuf[Len512] = { 0 };
    while (fgets(pbuf, sizeof(pbuf), fp)) {
        if (strncmp(pbuf, "cpu cores	:", strlen("cpu cores	:") == 0)) {
            sscanf(pbuf + strlen("cpu cores	:"), "%u", &m_CpuCores);
        } else if (strncmp(pbuf, "model name	:", strlen("model name	:")) == 0) {
            m_CpuModelName = pbuf + strlen("model name	:");
        }
    }
    fclose(fp);
    return NoneError;
}

Uint32 CSystemState::GetState()
{
    FILE* fp = fopen("/proc/stat", "r");
    if (!fp) {
        MkErrorLog("open system stat:/proc/stat failed, ignore");
        return false;
    }
    MkSystemState newState;
    char buf[Len1K] = { 0 };
    while (fgets(buf, sizeof(buf), fp)) {
        if (strncmp(buf, "cpu ", 4) != 0) {
            continue;
        }

        sscanf(buf + 5, "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
            &newState.User,
            &newState.Nice,
            &newState.Sys,
            &newState.Idle,
            &newState.IoWait,
            &newState.Irq,
            &newState.SoftIrq,
            &newState.Steal,
            &newState.Guest);
        break;
    }
    fclose(fp);
    Uint64 TotalValue;
    if (m_LastSystemState.TotalJiffies() > 0) {
        TotalValue = newState.TotalJiffies() - m_LastSystemState.TotalJiffies();
    }
    if (TotalValue > 0) {
        int64_t idle = newState.WorkJiffies() - m_LastSystemState.WorkJiffies();
        m_SystemCpuPercent = (double)idle / (double)TotalValue;
    }
    m_LastSystemState = newState;
    return NoneError;
}

CSystemState::~CSystemState()
{

}
